using System;
using System.Diagnostics;
using System.Text;
using UnityEngine;
using Debug = UnityEngine.Debug;
using static WinApi;
using System.Runtime.InteropServices;

public class User32Controller : IDisposable
{
#if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN
    IntPtr _hwnd = IntPtr.Zero; // 最终我们会尝试找到正确的渲染窗口句柄
    Rect _originalRect;

    IntPtr _originalWndProc = IntPtr.Zero;
    WNDPROC _customWndProc;
    // 常量
    const int SW_MAXIMIZE = 3;
    const int SW_MINIMIZE = 6;
    const int SW_RESTORE = 9;
    const int GWL_STYLE = -16;
    const int GWL_WNDPROC = -4;

    const uint SWP_NOSIZE = 0x0001;
    const uint SWP_NOMOVE = 0x0002;
    const uint SWP_NOZORDER = 0x0004;
    const uint SWP_NOACTIVATE = 0x0010;
    const uint SWP_FRAMECHANGED = 0x0020;

    const uint MONITOR_DEFAULTTONEAREST = 0x00000002;

    const uint WM_SYSCOMMAND = 0x0112;
    const uint WM_WINDOWPOSCHANGED = 0x0047;
    const uint WM_MOVE = 0x0003;
    const uint WM_SIZE = 0x0005;
    const uint WM_DPICHANGED = 0x02E0;
    const int SC_MAXIMIZE = 0xF030;

    // 样式
    const int WS_CAPTION = 0x00C00000;
    const int WS_THICKFRAME = 0x00040000;

    private const int DWMWA_NCRENDERING_POLICY = 2;
    private const int DWMWA_USE_IMMERSIVE_DARK_MODE = 20;
    const int HTCAPTION = 0x02;
    private const int WM_NCHITTEST = 0x0084;

    public User32Controller()
    {
        // 第一步：获取最有可能的 Unity 渲染窗口句柄（更鲁棒）
        _hwnd = GetUnityMainWindowHandle();

        if (_hwnd == IntPtr.Zero)
        {
            Debug.LogError("User32Controller: 无法找到合适的 Unity 窗口句柄。");
            return;
        }

        if (GetWindowRect(_hwnd, out RECT r))
            _originalRect = r.ToRect();

        // 注册自定义 WndProc
        _customWndProc = new WNDPROC(CustomWindowProc);
        _originalWndProc = SetWindowLongPtr(_hwnd, GWL_WNDPROC, Marshal.GetFunctionPointerForDelegate(_customWndProc));

        ApplyBorderlessStyleWithDwmFix();
    }
    IntPtr GetUnityMainWindowHandle()
    {
        int processId = Process.GetCurrentProcess().Id;
        IntPtr hWnd = IntPtr.Zero;

        EnumWindows((hWnd1, lParam) =>
        {
            if (IsWindowVisible(hWnd1))
            {
                GetWindowThreadProcessId(hWnd1, out ulong windowProcessId);
                if (windowProcessId == (ulong)processId)
                {
                    hWnd = hWnd1;
                    return false;
                }
            }
            return true;
        }, IntPtr.Zero);

        return hWnd;
    }

    // 更智能的查找逻辑：枚举同进程窗口，记录 class/title，优先选择包含 Unity 的 class 或 productName
    private IntPtr FindBestUnityWindowHandle()
    {
        int pid = Process.GetCurrentProcess().Id;
        IntPtr found = IntPtr.Zero;
        var candidates = new System.Collections.Generic.List<Tuple<IntPtr, string, string>>(); // hwnd, class, title

        EnumWindows((hWnd, lParam) =>
        {
            if (!IsWindowVisible(hWnd)) return true;

            GetWindowThreadProcessId(hWnd, out ulong windowPid);
            if (windowPid != (ulong)pid) return true;

            // get class name
            var cls = new StringBuilder(256);
            GetClassName(hWnd, cls, cls.Capacity);

            var title = new StringBuilder(1024);
            GetWindowText(hWnd, title, title.Capacity);

            string className = cls.ToString();
            string windowTitle = title.ToString();

            candidates.Add(Tuple.Create(hWnd, className, windowTitle));

            return true;
        }, IntPtr.Zero);

        // 优先：class 中包含 "Unity" 或 "UnityWndClass"
        foreach (var c in candidates)
        {
            if (!string.IsNullOrEmpty(c.Item2) && c.Item2.IndexOf("Unity", StringComparison.OrdinalIgnoreCase) >= 0)
            {
                Debug.Log($"User32Controller: 选择 class 包含 Unity 的窗口: {c.Item1} ({c.Item2})");
                return c.Item1;
            }
        }

        // 次优：标题匹配 Application.productName（如果可用）
        string product = Application.productName ?? "";
        foreach (var c in candidates)
        {
            if (!string.IsNullOrEmpty(c.Item3) && c.Item3.IndexOf(product, StringComparison.OrdinalIgnoreCase) >= 0)
            {
                Debug.Log($"User32Controller: 选择 title 匹配 productName 的窗口: {c.Item1} ({c.Item3})");
                return c.Item1;
            }
        }

        // 如果主窗口是容器（例如 Electron 风格或 wrapper），尝试枚举子窗口并选择含 Unity 的子窗口
        foreach (var c in candidates)
        {
            // 枚举子窗口
            IntPtr foundChild = IntPtr.Zero;
            EnumChildWindows(c.Item1, (childHwnd, lparam) =>
            {
                var clsb = new StringBuilder(256); GetClassName(childHwnd, clsb, clsb.Capacity);
                var titb = new StringBuilder(512); GetWindowText(childHwnd, titb, titb.Capacity);
                string cclass = clsb.ToString();
                string ctitle = titb.ToString();
                if (!string.IsNullOrEmpty(cclass) && cclass.IndexOf("Unity", StringComparison.OrdinalIgnoreCase) >= 0)
                {
                    foundChild = childHwnd;
                    return false;
                }
                return true;
            }, IntPtr.Zero);

            if (foundChild != IntPtr.Zero)
            {
                return foundChild;
            }
        }

        // 最后退回第一个候选（如果存在）
        if (candidates.Count > 0)
        {
            Debug.Log("User32Controller: 回退到第一个候选窗口。");
            return candidates[0].Item1;
        }

        return found;
    }

    private void ApplyBorderlessStyleWithDwmFix()
    {
        if (_hwnd == IntPtr.Zero) return;

        int style = GetWindowLong(_hwnd, GWL_STYLE);

        style &= ~WS_CAPTION;     // 必须移除
        style |= WS_THICKFRAME;   // 必须保留
        SetWindowLong(_hwnd, GWL_STYLE, style);

        int enable = 2;
        DwmSetWindowAttribute(_hwnd, DWMWA_NCRENDERING_POLICY, ref enable, sizeof(int));

        // 将标题栏高度变为 0（视觉上看不到标题栏，但 WS_CAPTION 仍然存在）
        MARGINS margins = new MARGINS()
        {
            topHeight = -1,
            leftWidth = 0,
            rightWidth = 0,
            bottomHeight = 0
        };
        DwmExtendFrameIntoClientArea(_hwnd, ref margins);

        // 通知窗口重新布局
        SetWindowPos(_hwnd, IntPtr.Zero, 0, 0, 0, 0,
            SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE);

        Debug.Log("Borderless style applied (WS_CAPTION kept for swapchain compatibility).");
    }

    private IntPtr CustomWindowProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
    {
        //----------------------------------------------------
        // 1) 处理拖动（最重要）
        //----------------------------------------------------
        if (msg == WM_NCHITTEST)
        {
            int x = (short)(lParam.ToInt32() & 0xFFFF);
            int y = (short)(lParam.ToInt32() >> 16);

            RECT rect;
            if (GetWindowRect(hWnd, out rect))
            {
                int localY = y - rect.Top;
                int localX = x - rect.Left;
                int windowWidth = rect.Right - rect.Left;

                // 仅当在顶部 50 像素内，且不在左右按钮区域时，才允许拖拽
                if (localY >= 0 && localY < 50)
                {
                    bool isLeftButtonArea = localX < 300;      // 左侧预留区（logo/菜单）
                    bool isRightButtonArea = localX > (windowWidth - 120); // 右侧系统按钮区

                    if (!isLeftButtonArea && !isRightButtonArea)
                    {
                        return (IntPtr)HTCAPTION;
                    }
                }
            }

            // 否则让 Windows 自行处理（或返回 HTCLIENT）
        }

        //----------------------------------------------------
        // 2) 自定义最大化逻辑
        //----------------------------------------------------
        if (msg == WM_SYSCOMMAND)
        {
            int cmd = wParam.ToInt32() & 0xFFF0;
            if (cmd == SC_MAXIMIZE)
            {
                Maximize();
                return IntPtr.Zero;
            }
        }

        //----------------------------------------------------
        // 3) 阻止 DPI 自适应（防止分辨率跳变）
        //----------------------------------------------------
        if (msg == WM_DPICHANGED)
        {
            return IntPtr.Zero; // 不让系统调整窗口大小
        }

        //----------------------------------------------------
        // 4) 跨屏强制重绘（保留）
        //----------------------------------------------------
        if (msg == WM_WINDOWPOSCHANGED || msg == WM_MOVE || msg == WM_SIZE)
        {
            try
            {
                DwmFlush();
                InvalidateRect(_hwnd, IntPtr.Zero, false);

                const uint RDW_INVALIDATE = 0x0001;
                const uint RDW_UPDATENOW = 0x0100;
                const uint RDW_ALLCHILDREN = 0x0080;

                RedrawWindow(_hwnd, IntPtr.Zero, IntPtr.Zero,
                    RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN);

                DwmFlush();
            }
            catch { }
        }

        //----------------------------------------------------
        // 最后调用原始窗口过程
        //----------------------------------------------------
        return CallWindowProc(_originalWndProc, hWnd, msg, wParam, lParam);
    }


    // 最大化（按显示器工作区）
    public void Maximize()
    {
        if (_hwnd == IntPtr.Zero) return;

        if (!GetWindowRect(_hwnd, out RECT rect)) return;
        _originalRect = rect.ToRect();

        POINT center = new POINT { X = (rect.Left + rect.Right) / 2, Y = (rect.Top + rect.Bottom) / 2 };
        IntPtr hMonitor = MonitorFromPoint(center, MONITOR_DEFAULTTONEAREST);
        if (hMonitor == IntPtr.Zero)
        {
            ShowWindow(_hwnd, SW_MAXIMIZE);
            return;
        }

        MONITORINFO info = new MONITORINFO(); info.cbSize = Marshal.SizeOf(info);
        if (GetMonitorInfo(hMonitor, ref info))
        {
            RECT w = info.rcWork;
            SetWindowPos(_hwnd, IntPtr.Zero, w.Left, w.Top, w.Right - w.Left, w.Bottom - w.Top, SWP_NOZORDER | SWP_NOACTIVATE);
        }
        else
            ShowWindow(_hwnd, SW_MAXIMIZE);
    }

    public void Restore()
    {
        if (_hwnd == IntPtr.Zero) return;
        SetWindowPos(_hwnd, IntPtr.Zero, (int)_originalRect.x, (int)_originalRect.y, (int)_originalRect.width, (int)_originalRect.height, SWP_NOZORDER | SWP_NOACTIVATE);
        // ShowWindow(_hwnd, SW_RESTORE);
    }

    public void Minimize()
    {
        if (_hwnd == IntPtr.Zero) return;
        ShowWindow(_hwnd, SW_MINIMIZE);
    }

    public void Dispose()
    {
        if (_hwnd != IntPtr.Zero && _originalWndProc != IntPtr.Zero)
        {
            SetWindowLongPtr(_hwnd, GWL_WNDPROC, _originalWndProc);
        }
        _hwnd = IntPtr.Zero;
    }

    internal void SetTopColor(bool v)
    {
        int darkMode = v ? 1 : 0; // TRUE

        DwmSetWindowAttribute(_hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE,
                   ref darkMode, sizeof(int));
    }
#endif
}
